home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / SMTPSERV.C < prev    next >
C/C++ Source or Header  |  1989-09-07  |  18KB  |  814 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <time.h>
  6. #ifdef UNIX
  7. #include <sys/types.h>
  8. #endif
  9. #if    defined(__STDC__) || defined(__TURBOC__)
  10. #include <stdarg.h>
  11. #endif
  12. #include <ctype.h>
  13. #include <setjmp.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "cmdparse.h"
  17. #include "socket.h"
  18. #include "proc.h"
  19. #include "smtp.h"
  20.  
  21. extern char Nospace[];
  22.  
  23. static struct list *expandalias __ARGS((struct list **head,char *user));
  24. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  25. static struct smtpsv *mail_create __ARGS((void));
  26. static char *getname __ARGS((char *cp));
  27. static void mail_clean __ARGS((struct smtpsv *mp));
  28. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  29. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  30. static void smtplog __ARGS((char *fmt,...));
  31. static void smtpserv __ARGS((int s,void *unused,void *p));
  32.  
  33. /* Command table */
  34. static char *commands[] = {
  35.     "helo",
  36. #define    HELO_CMD    0
  37.     "noop",
  38. #define    NOOP_CMD    1
  39.     "mail from:",
  40. #define    MAIL_CMD    2
  41.     "quit",
  42. #define    QUIT_CMD    3
  43.     "rcpt to:",
  44. #define    RCPT_CMD    4
  45.     "help",
  46. #define    HELP_CMD    5
  47.     "data",
  48. #define    DATA_CMD    6
  49.     "rset",
  50. #define    RSET_CMD    7
  51.     NULLCHAR
  52. };
  53.  
  54. /* Reply messages */
  55. static char help[] = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  56. static char banner[] = "220 %s SMTP ready\r\n";
  57. static char closing[] = "221 Closing\r\n";
  58. static char ok[] = "250 Ok\r\n";
  59. static char reset[] = "250 Reset state\r\n";
  60. static char sent[] = "250 Sent\r\n";
  61. static char ourname[] = "250 %s, Share and Enjoy!\r\n";
  62. static char enter[] = "354 Enter mail, end with .\r\n";
  63. static char ioerr[] = "452 Temp file write error\r\n";
  64. static char badcmd[] = "500 Command unrecognized\r\n";
  65. static char syntax[] = "501 Syntax error\r\n";
  66. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  67. static char unknown[] = "550 <%s> address unknown\r\n";
  68.  
  69. static int Ssmtp = -1; /* prototype socket for service */
  70.  
  71. /* Start up SMTP receiver service */
  72. int
  73. smtp1(argc,argv,p)
  74. int argc;
  75. char *argv[];
  76. void *p;
  77. {
  78.     struct sockaddr_in lsocket;
  79.     int s;
  80.  
  81.     if(Ssmtp != -1){
  82.         freeargs(argc,argv);
  83.         return 0;
  84.     }
  85.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  86.     chname(Curproc,"SMTP listener");
  87.  
  88.     lsocket.sin_family = AF_INET;
  89.     lsocket.sin_addr.s_addr = Ip_addr;
  90.     if(argc < 2)
  91.         lsocket.sin_port = IPPORT_SMTP;
  92.     else
  93.         lsocket.sin_port = atoi(argv[1]);
  94.  
  95.     freeargs(argc,argv);
  96.     Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  97.     bind(Ssmtp,(char *)&lsocket,sizeof(lsocket));
  98.     listen(Ssmtp,1);
  99.     for(;;){
  100.         if((s = accept(Ssmtp,NULLCHAR,(int *)NULL)) == -1)
  101.             break;    /* Service is shutting down */
  102.  
  103.         /* Spawn a server */
  104.         newproc("SMTP server",2048,smtpserv,s,NULL,NULL);
  105.     }
  106.     return 0;
  107. }
  108.  
  109. /* Shutdown SMTP service (existing connections are allowed to finish) */
  110. int
  111. smtp0(argc,argv,p)
  112. int argc;
  113. char *argv[];
  114. void *p;
  115. {
  116.     close_s(Ssmtp);
  117.     Ssmtp = -1;
  118.     return 0;
  119. }
  120.  
  121. static void
  122. smtpserv(s,unused,p)
  123. int s;
  124. void *unused;
  125. void *p;
  126. {
  127.     struct smtpsv *mp;
  128.     char **cmdp,buf[LINELEN],*arg,*cp,*cmd;
  129.     int cnt;
  130.     char address_type;
  131.  
  132.     sockowner(s,Curproc);        /* We own it now */
  133.     log(s,"open SMTP");
  134.  
  135.     if((mp = mail_create()) == NULLSMTPSV){
  136.         printf(Nospace);
  137.         log(s,"close SMTP - no space");
  138.         close_s(s);
  139.         return;
  140.     }
  141.     mp->s = s;
  142.  
  143.     (void) usprintf(s,banner,Hostname);
  144.  
  145. loop:    if ((cnt = recvline(s,buf,sizeof(buf))) == -1) {
  146.         /* He closed on us */
  147.         goto quit;
  148.     }
  149.     if(cnt < 4){
  150.         /* Can't be a legal command */
  151.         usprintf(mp->s,badcmd);
  152.         goto loop;
  153.     }    
  154.     rip(buf);
  155.     cmd = buf;
  156.  
  157.     /* Translate entire buffer to lower case */
  158.     for(cp = cmd;*cp != '\0';cp++)
  159.         *cp = tolower(*cp);
  160.  
  161.     /* Find command in table; if not present, return syntax error */
  162.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  163.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  164.             break;
  165.     if(*cmdp == NULLCHAR){
  166.         (void) usprintf(mp->s,badcmd);
  167.         goto loop;
  168.     }
  169.     arg = &cmd[strlen(*cmdp)];
  170.     /* Skip spaces after command */
  171.     while(*arg == ' ')
  172.         arg++;
  173.     /* Execute specific command */
  174.     switch(cmdp-commands) {
  175.     case HELO_CMD:
  176.         free(mp->system);
  177.         if((mp->system = strdup(arg)) == NULLCHAR){
  178.             /* If the system is out of memory, just close */
  179.             goto quit;
  180.         } else {
  181.             (void) usprintf(mp->s,ourname,Hostname);
  182.         }
  183.         break;
  184.     case NOOP_CMD:
  185.         (void) usprintf(mp->s,ok);
  186.         break;
  187.     case MAIL_CMD:
  188.         if((cp = getname(arg)) == NULLCHAR){
  189.             (void) usprintf(mp->s,syntax);
  190.             break;
  191.         }
  192.         free(mp->from);
  193.         if((mp->from = strdup(cp)) == NULLCHAR){
  194.             /* If the system is out of memory, just close */
  195.             goto quit;
  196.         } else {
  197.             (void) usprintf(mp->s,ok);
  198.         }
  199.         break;
  200.     case QUIT_CMD:
  201.         (void) usprintf(mp->s,closing);
  202.         goto quit;
  203.     case RCPT_CMD:    /* Specify recipient */
  204.         if((cp = getname(arg)) == NULLCHAR){
  205.             (void) usprintf(mp->s,syntax);
  206.             break;
  207.         }
  208.  
  209.         /* check if address is ok */
  210.         if ((address_type = validate_address(cp)) == BADADDR) {
  211.             (void) usprintf(mp->s,unknown,cp);
  212.             break;
  213.         }
  214.         /* if a local address check for an alias */
  215.         if (address_type == LOCAL)
  216.             expandalias(&mp->to, cp);
  217.         else
  218.             /* a remote address is added to the list */
  219.             addlist(&mp->to, cp, address_type);
  220.  
  221.         (void) usprintf(mp->s,ok);
  222.         break;
  223.     case HELP_CMD:
  224.         (void) usprintf(mp->s,help);
  225.         break;
  226.     case DATA_CMD:
  227.         if(mp->to == NULLLIST)
  228.             (void) usprintf(mp->s,needrcpt);
  229.         else if ((mp->data = tmpfile()) == NULLFILE)
  230.             (void) usprintf(mp->s,ioerr);
  231.          else
  232.             getmsgtxt(mp);
  233.         break;
  234.     case RSET_CMD:
  235.         del_list(mp->to);
  236.         mp->to = NULLLIST;
  237.         (void) usprintf(mp->s,reset);
  238.         break;
  239.     }
  240.     goto loop;
  241.  
  242. quit:
  243.     log(mp->s,"close SMTP");
  244.     close_s(mp->s);
  245.     mail_clean(mp);
  246. }
  247.  
  248. /* read the message text */
  249. static int
  250. getmsgtxt(mp)
  251. struct smtpsv *mp;
  252. {
  253.     char buf[LINELEN];
  254.     register char *p = buf;
  255.     long t;
  256.  
  257.     /* Add timestamp; ptime adds newline */
  258.     time(&t);
  259.     fprintf(mp->data,"Received: ");
  260.     if(mp->system != NULLCHAR)
  261.         fprintf(mp->data,"from %s ",mp->system);
  262.     fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  263.             Hostname, get_msgid(), ptime(&t));
  264.     if(ferror(mp->data)){
  265.         (void) usprintf(mp->s,ioerr);
  266.         return 1;
  267.     } else {
  268.         (void) usprintf(mp->s,enter);
  269.     }
  270.     while(1) {
  271.         if(recvline(mp->s,p,sizeof(buf)) == -1){
  272.             return 1;
  273.         }
  274.         rip(p);
  275.         /* check for end of message ie a . or escaped .. */
  276.         if (*p == '.') {
  277.             if (*++p == '\0') {
  278.                 /* Also sends appropriate response */
  279.                 if (mailit(mp->data,mp->from,mp->to) != 0)
  280.                     (void) usprintf(mp->s,ioerr);
  281.                 else
  282.                     (void) usprintf(mp->s,sent);
  283.                 fclose(mp->data);
  284.                 mp->data = NULLFILE;
  285.                 del_list(mp->to);
  286.                 mp->to = NULLLIST;
  287.                 return 0;
  288.             } else if (!(*p == '.' && *(p+1) == '\0'))
  289.                 p--;
  290.         }
  291.         /* for UNIX mail compatiblity */
  292.         if (strncmp(p,"From ",5) == 0)
  293.             (void) putc('>',mp->data);
  294.         /* Append to data file */
  295.         if(fprintf(mp->data,"%s\n",p) < 0) {
  296.             (void) usprintf(mp->s,ioerr);
  297.             return 1;
  298.         }
  299.  
  300.     }
  301.     return 0;
  302. }
  303.  
  304. /* Create control block, initialize */
  305. static struct smtpsv *
  306. mail_create()
  307. {
  308.     register struct smtpsv *mp;
  309.  
  310.     if((mp = (struct smtpsv *)calloc(1,sizeof(struct smtpsv))) == NULLSMTPSV)
  311.         return NULLSMTPSV;
  312.     return mp;
  313. }
  314.  
  315. /* Free resources, delete control block */
  316. static void
  317. mail_clean(mp)
  318. register struct smtpsv *mp;
  319. {
  320.     if (mp == NULLSMTPSV)
  321.         return;
  322.     free(mp->system);
  323.     free(mp->from);
  324.     if(mp->data != NULLFILE)
  325.         fclose(mp->data);
  326.     del_list(mp->to);
  327.     free((char *)mp);
  328. }
  329.  
  330.  
  331. /* Given a string of the form <user@host>, extract the part inside the
  332.  * brackets and return a pointer to it.
  333.  */
  334. static char *
  335. getname(cp)
  336. register char *cp;
  337. {
  338.     register char *cp1;
  339.  
  340.     if ((cp = strchr(cp,'<')) == NULLCHAR)
  341.         return NULLCHAR;
  342.     cp++;    /* cp -> first char of name */
  343.     if ((cp1 = strchr(cp,'>')) == NULLCHAR)
  344.         return NULLCHAR;
  345.     *cp1 = '\0';
  346.     return cp;
  347. }
  348.  
  349.         
  350. /* General mailit function. It takes a list of addresses which have already
  351. ** been verified and expanded for aliases. Base on the current mode the message
  352. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  353. */
  354. static int
  355. mailit(data,from,tolist)
  356. FILE *data;
  357. char *from;
  358. struct list *tolist;
  359. {
  360.     register struct list *ap;
  361.     register FILE *fp;
  362.     int c;
  363.     char    mailbox[50];
  364.     char    *cp;
  365.     char    *desthost;
  366.     int    fail = 0;
  367.     time_t    t;
  368.  
  369.     if ((Smtpmode & QUEUE) != 0)
  370.         return(router_queue(data,from,tolist));
  371.  
  372.     for(ap = tolist;ap != NULLLIST;ap = ap->next) {
  373.  
  374.         rewind(data);
  375.  
  376.         /* non local mail queue it */
  377.         if (ap->type == DOMAIN) {
  378.             if ((desthost = strchr(ap->val,'@')) != NULLCHAR)
  379.                 desthost++;
  380.             fail = queuejob(data,desthost,ap->val,from);
  381.         } else {
  382.             /* strip off host name */
  383.             if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  384.                 *cp = '\0';
  385.  
  386.             /* truncate long user names */
  387.             if (strlen(ap->val) > MBOXLEN)
  388.                 ap->val[MBOXLEN] = '\0';
  389.  
  390.             /* if mail file is busy save it in our smtp queue
  391.              * and let the smtp daemon try later.
  392.              */
  393.             if (mlock(Mailspool,ap->val))
  394.                 fail = queuejob(data,Hostname,ap->val,from);
  395.             else {
  396.                 sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  397. #ifndef    AMIGA
  398.                 if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE) {
  399. #else
  400.                     (void) fseek(fp, 0L, 2);
  401. #endif
  402.                     time(&t);
  403.                     fprintf(fp,
  404.                     "From %s %s",from,ctime(&t));
  405.                     while((c = getc(data)) != EOF)
  406.                         if(putc(c,fp) == EOF)
  407.                             break;
  408.                     if(ferror(fp))
  409.                         fail = 1;
  410.                     else
  411.                         fprintf(fp,"\n");
  412.                     /* Leave a blank line between msgs */
  413.                     fclose(fp);
  414.                     printf("New mail arrived for %s\n",ap->val);
  415.                 } else 
  416.                     fail = 1;
  417.                 (void) rmlock(Mailspool,ap->val);
  418.                 if (fail)
  419.                     break;
  420.                 smtplog("deliver: To: %s From: %s",ap->val,from);
  421.             }
  422.         }
  423.     }
  424.     return fail;
  425. }
  426.  
  427. /* Return Date/Time in Arpanet format in passed string */
  428. char *
  429. ptime(t)
  430. long *t;
  431. {
  432.     /* Print out the time and date field as
  433.      *        "DAY day MONTH year hh:mm:ss ZONE"
  434.      */
  435.     register struct tm *ltm;
  436.     static char tz[4];
  437.     static char str[40];
  438.     char *p;
  439.     static char *days[7] = {
  440.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  441.  
  442.     static char *months[12] = {
  443.         "Jan","Feb","Mar","Apr","May","Jun",
  444.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  445.  
  446.     /* Read the system time */
  447.     ltm = localtime(t);
  448.  
  449.     if (*tz == '\0')
  450.         if ((p = getenv("TZ")) == NULL)
  451.             strcpy(tz,"GMT");
  452.         else
  453.             strncpy(tz,p,3);
  454.  
  455.     /* rfc 822 format */
  456.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  457.         days[ltm->tm_wday],
  458.         ltm->tm_mday,
  459.         months[ltm->tm_mon],
  460.         ltm->tm_year,
  461.         ltm->tm_hour,
  462.         ltm->tm_min,
  463.         ltm->tm_sec,
  464.         tz);
  465.     return(str);
  466. }
  467.  
  468. long 
  469. get_msgid()
  470. {
  471.     char sfilename[LINELEN];
  472.     char s[20];
  473.     register long sequence = 0;
  474.     FILE *sfile;
  475.  
  476.     sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  477.     sfile = fopen(sfilename,READ_TEXT);
  478.  
  479.     /* if sequence file exists, get the value, otherwise set it */
  480.     if (sfile != NULL) {
  481.         (void) fgets(s,sizeof(s),sfile);
  482.         sequence = atol(s);
  483.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  484.         if (sequence < 0L || sequence > 99999999L )
  485.             sequence = 0;
  486.         fclose(sfile);
  487.     }
  488.  
  489.     /* increment sequence number, and write to sequence file */
  490.     sfile = fopen(sfilename,WRITE_TEXT);
  491.     fprintf(sfile,"%ld",++sequence);
  492.     fclose(sfile);
  493.     return sequence;
  494. }
  495.  
  496. #ifdef    MSDOS
  497. /* Illegal characters in a DOS filename */
  498. static char baddoschars[] = "\"[]:|<>+=;,";
  499. #endif
  500.  
  501. /* test if mail address is valid */
  502. int
  503. validate_address(s)
  504. char *s;
  505. {
  506.     char *cp;
  507.     int32 addr;
  508.  
  509.     /* if address has @ in it the check dest address */
  510.     if ((cp = strrchr(s,'@')) != NULLCHAR) {
  511.         cp++;
  512.         /* 1st check if its our hostname
  513.         * if not then check the hosts file and see
  514.         * if we can resolve ther address to a know site
  515.         * or one of our aliases
  516.         */
  517.         if (strcmp(cp,Hostname) != 0) {
  518.             if ((addr = mailroute(cp)) == 0
  519.                 && (Smtpmode & QUEUE) == 0)
  520.                 return BADADDR;
  521.             if (addr != Ip_addr)
  522.                 return DOMAIN;
  523.         }
  524.         
  525.         /* on a local address remove the host name part */
  526.         *--cp = '\0';
  527.     }
  528.  
  529.     /* if using an external router leave address alone */
  530.     if ((Smtpmode & QUEUE) != 0)
  531.         return LOCAL;
  532.  
  533.     /* check for the user%host hack */
  534.     if ((cp = strrchr(s,'%')) != NULLCHAR) {
  535.         *cp = '@';
  536.         cp++;
  537.         /* reroute based on host name following the % seperator */
  538.         if (mailroute(cp) == 0)
  539.             return BADADDR;
  540.         else
  541.             return DOMAIN;
  542.     }
  543.  
  544. #ifdef MSDOS    /* dos file name checks */
  545.     /* Check for characters illegal in MS-DOS file names */
  546.     for(cp = baddoschars;*cp != '\0';cp++){
  547.         if(strchr(s,*cp) != NULLCHAR)
  548.             return BADADDR;    
  549.     }
  550. #endif
  551.     return LOCAL;
  552. }
  553.  
  554. /* place a mail job in the outbound queue */
  555. int
  556. queuejob(dfile,host,to,from)
  557. FILE *dfile;
  558. char *host,*to,*from;
  559. {
  560.     FILE *fp;
  561.     char tmpstring[50];
  562.     char prefix[9];
  563.     register int c;
  564.  
  565.     sprintf(prefix,"%ld",get_msgid());
  566.     smtplog("queue job %s To: %s From: %s",prefix,to,from);
  567.     mlock(Mailqdir,prefix);
  568.     sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  569.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  570.         (void) rmlock(Mailqdir,prefix);
  571.         return 1;
  572.     }
  573.     while((c = getc(dfile)) != EOF)
  574.         if(putc(c,fp) == EOF)
  575.             break;
  576.     if(ferror(fp)){
  577.         fclose(fp);
  578.         (void) rmlock(Mailqdir,prefix);
  579.         return 1;
  580.     }
  581.     fclose(fp);
  582.     sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  583.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  584.         (void) rmlock(Mailqdir,prefix);
  585.         return 1;
  586.     }
  587.     fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  588.     fclose(fp);
  589.     (void) rmlock(Mailqdir,prefix);
  590.     return 0;
  591. }
  592.  
  593. /* Deliver mail to the appropriate mail boxes */
  594. static int
  595. router_queue(data,from,to)
  596. FILE *data;
  597. char *from;
  598. struct list *to;
  599. {
  600.     int c;
  601.     register struct list *ap;
  602.     FILE *fp;
  603.     char tmpstring[50];
  604.     char prefix[9];
  605.  
  606.     sprintf(prefix,"%ld",get_msgid());
  607.     mlock(Routeqdir,prefix);
  608.     sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  609.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  610.         (void) rmlock(Routeqdir,prefix);
  611.         return 1;
  612.     }
  613.     rewind(data);
  614.     while((c = getc(data)) != EOF)
  615.         if(putc(c,fp) == EOF)
  616.             break;
  617.     if(ferror(fp)){
  618.         fclose(fp);
  619.         (void) rmlock(Routeqdir,prefix);
  620.         return 1;
  621.     }
  622.     fclose(fp);
  623.     sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  624.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  625.         (void) rmlock(Routeqdir,prefix);
  626.         return 1;
  627.     }
  628.     fprintf(fp,"From: %s\n",from);
  629.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  630.         fprintf(fp,"To: %s\n",ap->val);
  631.     }
  632.     fclose(fp);
  633.     (void) rmlock(Routeqdir,prefix);
  634.     smtplog("rqueue job %s From: %s",prefix,from);
  635.     return 0;
  636. }
  637.  
  638. /* add an element to the front of the list pointed to by head 
  639. ** return NULLLIST if out of memory.
  640. */
  641. struct list *
  642. addlist(head,val,type)
  643. struct list **head;
  644. char *val;
  645. int type;
  646. {
  647.     register struct list *tp;
  648.  
  649.     tp = (struct list *)calloc(1,sizeof(struct list));
  650.     if (tp == NULLLIST)
  651.         return NULLLIST;
  652.  
  653.     tp->next = NULLLIST;
  654.  
  655.     /* allocate storage for the char string */
  656.     if ((tp->val = strdup(val)) == NULLCHAR) {
  657.         (void) free((char *)tp);
  658.         return NULLLIST;
  659.     }
  660.     tp->type = type;
  661.  
  662.     /* add entry to front of existing list */
  663.     if (*head == NULLLIST)
  664.         *head = tp;
  665.     else {
  666.         tp->next = *head;
  667.         *head = tp;
  668.     }
  669.     return tp;
  670.  
  671. }
  672.  
  673. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  674. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  675.  
  676. /* check for and alias and expand alias into a address list */
  677. static struct list *
  678. expandalias(head, user)
  679. struct list **head;
  680. char *user;
  681. {
  682.     FILE *fp;
  683.     register char *s,*p;
  684.     int inalias;
  685.     struct list *tp;
  686.     char buf[LINELEN];
  687.     
  688.         /* no alias file found */
  689.     if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE)
  690.         return addlist(head, user, LOCAL);
  691.  
  692.     inalias = 0;
  693.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  694.         p = buf;
  695.         if ( *p == '#' || *p == '\0')
  696.             continue;
  697.         rip(p);
  698.  
  699.         /* if not in an matching entry skip continuation lines */
  700.         if (!inalias && isspace(*p))
  701.             continue;
  702.  
  703.         /* when processing an active alias check for a continuation */
  704.         if (inalias) {
  705.             if (!isspace(*p)) 
  706.                 break;    /* done */
  707.         } else {
  708.             s = p;
  709.             SKIPWORD(p);
  710.             *p++ = '\0';    /* end the alias name */
  711.             if (strcmp(s,user) != 0)
  712.                 continue;    /* no match go on */
  713.             inalias = 1;
  714.         }
  715.  
  716.         /* process the recipients on the alias line */
  717.         SKIPSPACE(p);
  718.         while(*p != '\0' && *p != '#') {
  719.             s = p;
  720.             SKIPWORD(p);
  721.             if (*p != '\0')
  722.                 *p++ = '\0';
  723.  
  724.             /* find hostname */
  725.             if (strchr(s,'@') != NULLCHAR)
  726.                 tp = addlist(head,s,DOMAIN);
  727.             else
  728.                 tp = addlist(head,s,LOCAL);
  729.             SKIPSPACE(p);
  730.         }
  731.     }
  732.     (void) fclose(fp);
  733.  
  734.     if (inalias)    /* found and processed and alias. */
  735.         return tp;
  736.  
  737.     /* no alias found treat as a local address */
  738.     return addlist(head, user, LOCAL);
  739. }
  740.  
  741. #if    defined(ANSIPROTO) && !defined(AMIGA)
  742. static void
  743. smtplog(char *fmt, ...)
  744. {
  745.     va_list ap;
  746.     char *cp;
  747.     long t;
  748.     FILE *fp;
  749.  
  750.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  751.         return;
  752.     time(&t);
  753.     cp = ctime(&t);
  754.     rip(cp);
  755.     fprintf(fp,"%s ",cp);
  756.     va_start(ap,fmt);
  757.     vfprintf(fp,fmt,ap);
  758.     va_end(ap);
  759.     fprintf(fp,"\n");
  760.     fclose(fp);
  761. }
  762.  
  763. #else
  764.  
  765. static void
  766. smtplog(fmt,arg1,arg2,arg3,arg4)
  767. char *fmt;
  768. int arg1,arg2,arg3,arg4;
  769. {
  770.     char *cp;
  771.     long t;
  772.     FILE *fp;
  773.  
  774.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  775.         return;
  776.     time(&t);
  777.     cp = ctime(&t);
  778.     rip(cp);
  779.     fprintf(fp,"%s ",cp);
  780.     fprintf(fp,fmt,arg1,arg2,arg3,arg4);
  781.     fprintf(fp,"\n");
  782.     fclose(fp);
  783. }
  784. #endif
  785.  
  786. /* send mail to a single user. Can be called from the ax24 mailbox or
  787. ** from the return mail function in the smtp client 
  788. */
  789. int
  790. mailuser(data,from,to)
  791. FILE *data;
  792. char *from;
  793. char *to;
  794. {
  795.  
  796.         int address_type, ret;
  797.         struct list *tolist = NULLLIST;
  798.  
  799.         /* check if address is ok */
  800.         if ((address_type = validate_address(to)) == BADADDR) {
  801.             return 1;
  802.         }
  803.         /* if a local address check for an alias */
  804.         if (address_type == LOCAL)
  805.             expandalias(&tolist, to);
  806.         else
  807.             /* a remote address is added to the list */
  808.             addlist(&tolist, to, address_type);
  809.         ret = mailit(data,from,tolist);
  810.         del_list(tolist);
  811.         return ret;
  812.  
  813. }
  814.